package com.ppblock.shirox.core.impl;

import com.ppblock.shirox.core.*;
import com.ppblock.shirox.surpport.ShiroxPermission;
import com.ppblock.shirox.surpport.RequiresPermissions;
import com.ppblock.shirox.surpport.ShiroxRole;
import com.ppblock.shirox.surpport.ShiroxConfigure;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 授权认证管理实现
 * @author yangjian
 * @since 17-12-5.
 */
public class AuthorizationManager implements SubjectManager {

	/**
	 * 当前请求的 session 会话
	 */
	private HttpSession httpSession;

	/**
	 * 认证域的实例,这个一般是由业务端实现, 通过外部注入进来, 允许注入多个域
     */
	private List<AuthorizationRealm> realms;

	private ShiroxConfigure shiroxConfigure;

	public AuthorizationManager() {}

	/**
	 * 绑定　session 会话
	 * @param session
	 */
	@Override
	public void bindSession(HttpSession session) {
		this.httpSession = session;
	}

	/**
	 * 添加认证域
	 * @param realm
	 */
	public void addRealm(AuthorizationRealm realm) {
		if (null == this.realms) {
			this.realms = new ArrayList<>();
		}
		this.realms.add(realm);
	}

	@Override
	public AuthorizationInfo getAuthorizationInfo() {
		return (AuthorizationInfo) httpSession.getAttribute(AUTHORIZE_INFO_SESSION_KEY);
	}

	/**
	 * 添加授权信息
	 * 当前算法是把多个授权实体的权限(Permissions) 和角色(Roles) 合并
	 * @param info
	 */
	public void addAuthorizationInfo(AuthorizationInfo info) {

		AuthorizationInfo oriInfo = this.getAuthorizationInfo();
		if (null == oriInfo) {
			this.setAuthorizationInfo(info);
			return;
		}
		info.getPermissions().forEach((permission) -> {
			oriInfo.getPermissions().add(permission);
		});
		info.getRoles().forEach((role) -> {
			oriInfo.getRoles().add(role);
		});
		// 重新设置 AuthorizationInfo
		this.setAuthorizationInfo(oriInfo);

	}

	/**
	 * 设置授权信息
	 * @param info
	 */
	public void setAuthorizationInfo(AuthorizationInfo info) {
		httpSession.setAttribute(AUTHORIZE_INFO_SESSION_KEY, info);
	}

	@Override
	public AuthenticationInfoEntity getAuthenticationInfo() {
		return (AuthenticationInfoEntity) httpSession.getAttribute(AUTHEN_INFO_SESSION_KEY);
	}

	@Override
	public AuthenticationInfo getPrimaryAuthenticationInfo() {
		return this.getAuthenticationInfo().getPrimaryAuthenticationInfo();
	}

	public void setAuthenticationInfo(AuthenticationInfoEntity entity) {
		httpSession.setAttribute(AUTHEN_INFO_SESSION_KEY, entity);
	}

	/**
	 * 登录操作
	 * @param token
     */
	@Override
	public void login(AuthenticationToken token) {

		AuthenticationInfoEntity entity = new AuthenticationInfoEntity();
		this.realms.forEach(realm -> {
			//获取身份认证信息
			AuthenticationInfo authenticationInfo = realm.doGetAuthenticationInfo(token);
			if (null != authenticationInfo) {
				entity.addAuthenticationInfo(authenticationInfo);
				//获取角色和权限信息
				AuthorizationInfo authorizationInfo = realm.doGetAuthorizationInfo(authenticationInfo);
				if (null != authorizationInfo) {
					this.addAuthorizationInfo(authorizationInfo);
				}
			}

		});

		this.setAuthenticationInfo(entity);
	}

	@Override
	public void logout() {
		//删除 session
		httpSession.setAttribute(AUTHEN_INFO_SESSION_KEY, null);
	}

	@Override
	public boolean isAuthorized() {
		return httpSession.getAttribute(AUTHEN_INFO_SESSION_KEY) != null;
	}

	@Override
	public boolean hasPermission(String operation) {

		AuthorizationInfo info = this.getAuthorizationInfo();
		if (null == info || null == operation) {
			return false;
		}
		//判断是否超级管理员
		if (isRoot(info.getRoles())) {
			return true;
		}
		//判断权限
		List<ShiroxPermission> permissions = info.getPermissions();
		if (null == permissions || permissions.size() == 0) {
			return false;
		}
		Iterator<ShiroxPermission> iterator = permissions.iterator();
		while (iterator.hasNext()) {
			if (iterator.next().getPermissionValue().equals(operation.trim())) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean hasPermission(ShiroxPermission permission) {
		return hasPermission(permission.getPermissionValue());
	}

	@Override
	public boolean hasAnyPermissions(List permissions) {

		if (null == permissions || permissions.size() == 0) {
			return false;
		}
		for (Object p : permissions) {
			if (hasPermission((String) p)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean hasAllPermissions(List permissions) {

		if (null == permissions || permissions.size() == 0) {
			return true;
		}

		for (Object p : permissions) {
			if (!hasPermission((String) p)) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 获取权限注解
	 * @param handler
	 * @return
	 */
	public static String getPermissionAnnotation(Object handler) {

		if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
			RequiresPermissions annotation = ((HandlerMethod) handler).getMethodAnnotation(RequiresPermissions.class);
			if (null != annotation) {
				return annotation.value()[0];
			}
		}
		return null;
	}

	/**
	 * 是否超级管理员
	 * @param roles
	 * @return
	 */
	private boolean isRoot(List<ShiroxRole> roles) {

		if (null == roles || roles.size() == 0) {
			return false;
		}
		for (int i = 0; i < roles.size(); i++) {
			if (roles.get(i).isRoot()) {
				return true;
			}
		}
		return false;
	}

	@Override
	public ShiroxConfigure getShiroxConfigure() {
		return shiroxConfigure;
	}

	@Override
	public void setShiroxConfigure(ShiroxConfigure shiroxConfigure) {
		this.shiroxConfigure = shiroxConfigure;
	}
}
